﻿namespace Jsl.FxCop
{
    using System.Data;
    using Jsl.FxCop.Targets;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using Microsoft.VisualStudio.CodeAnalysis.Extensibility;

    [TestClass]
    public class When_getting_a_table_from_a_typed_DataSet
    {
        [TestMethod]
        public void No_problems_if_the_DataSet_is_not_typed()
        {
            new UseTypedDataSetFeatures()
                .RunMethodRule(
                    () =>
                    {
                        var ds = (DataSet)null;
                        var ignore = ds.Tables["TestTable"];
                    })
                .HasNoMoreProblems();
        }

        [TestMethod]
        public void No_problems_if_typed_table_property_is_used()
        {
            new UseTypedDataSetFeatures()
                .RunMethodRule(
                    () =>
                    {
                        var ds = (TestDataSet)null;
                        var ignore = ds.TestTable;
                    })
                .HasNoMoreProblems();
        }

        [TestMethod]
        public void Suggest_uses_table_property_if_typed_DataSet_and_table_exists()
        {
            new UseTypedDataSetFeatures()
                .RunMethodRule(
                    () =>
                    {
                        var ds = (TestDataSet)null;
                        var ignore = ds.Tables["TestTable"];
                    })
                .HasProblem(
                    100,
                    FixCategories.NonBreaking,
                    MessageLevel.Warning,
                    "Use ds.TestTable instead of ds.Tables[\"TestTable\"].")
                .HasNoMoreProblems();
        }
    }

    [TestClass]
    public class When_creating_a_new_row_in_a_typed_DataTable
    {
        [TestMethod]
        public void No_problem_if_table_is_not_typed()
        {
            new UseTypedDataSetFeatures()
                .RunMethodRule(
                    () =>
                    {
                        var dataTable = (DataTable)null;
                        var row = dataTable.NewRow();
                    })
                .HasNoMoreProblems();
        }

        [TestMethod]
        public void No_problem_if_typed_NewRow_is_used()
        {
            new UseTypedDataSetFeatures()
                .RunMethodRule(
                    () =>
                    {
                        var ds = (TestDataSet)null;
                        var row = ds.TestTable.NewTestTableRow();
                    })
                .HasNoMoreProblems();
        }

        [TestMethod]
        public void Suggest_using_typed_NewRow_instead()
        {
            new UseTypedDataSetFeatures()
                .RunMethodRule(
                    () =>
                    {
                        var ds = (TestDataSet)null;
                        var row = ds.TestTable.NewRow();
                    })
                .HasProblem(
                    100,
                    FixCategories.NonBreaking,
                    MessageLevel.Warning,
                    "Use table.NewTestTableRow() instead of table.NewRow().")
                .HasNoMoreProblems();
        }
    }

    [TestClass]
    public class When_adding_a_row_to_a_typed_DataSet
    {
        [TestMethod]
        public void No_problem_if_table_is_not_typed()
        {
            new UseTypedDataSetFeatures()
                .RunMethodRule(
                    () =>
                    {
                        var dataTable = (DataTable)null;
                        var row = (DataRow)null;
                        dataTable.Rows.Add(row);
                    })
                .HasNoMoreProblems();
        }

        [TestMethod]
        public void No_problem_if_typed_AddXxxRow_is_used()
        {
            new UseTypedDataSetFeatures()
                .RunMethodRule(
                    () =>
                    {
                        var ds = (TestDataSet)null;
                        var row = (TestDataSet.TestTableRow)null;
                        ds.TestTable.AddTestTableRow(row);
                    })
                .HasNoMoreProblems();
        }

        [TestMethod]
        public void No_problem_if_Add_is_used_with_untyped_DataRow()
        {
            new UseTypedDataSetFeatures()
                .RunMethodRule(
                    () =>
                    {
                        var ds = (TestDataSet)null;
                        var row = (DataRow)null;
                        ds.TestTable.Rows.Add(row);
                    })
                .HasNoMoreProblems();
        }

        [TestMethod]
        public void Suggest_using_NewXxxRow_if_DataRow_is_typed()
        {
            new UseTypedDataSetFeatures()
                .RunMethodRule(
                    () =>
                    {
                        var ds = (TestDataSet)null;
                        var row = (TestDataSet.TestTableRow)null;
                        ds.TestTable.Rows.Add(row);
                    })
                .HasProblem(
                    100,
                    FixCategories.NonBreaking,
                    MessageLevel.Warning,
                    "Use table.AddTestTableRow(row) instead of table.Rows.Add(row).")
                .HasNoMoreProblems();
        }

        [TestMethod]
        public void The_AddXxxRow_method_defined_in_the_typed_DataSet_is_ignored()
        {
            var addTestTableRowMethod = typeof(TestDataSet.TestTableDataTable).GetTypeNode()
                .GetMethod(method => (method.Name.Name == "AddTestTableRow") && (method.Parameters.Count == 1));

            new UseTypedDataSetFeatures()
                .RunMethodRule(addTestTableRowMethod)
                .HasNoMoreProblems();
        }
    }

    [TestClass]
    public class When_removing_a_row_from_a_typed_DataSet
    {
        [TestMethod]
        public void No_problem_if_table_is_not_typed()
        {
            new UseTypedDataSetFeatures()
                .RunMethodRule(
                    () =>
                    {
                        var dataTable = (DataTable)null;
                        var row = (DataRow)null;
                        dataTable.Rows.Remove(row);
                    })
                .HasNoMoreProblems();
        }

        [TestMethod]
        public void No_problem_if_typed_RemoveXxxRow_is_used()
        {
            new UseTypedDataSetFeatures()
                .RunMethodRule(
                    () =>
                    {
                        var ds = (TestDataSet)null;
                        var row = (TestDataSet.TestTableRow)null;
                        ds.TestTable.RemoveTestTableRow(row);
                    })
                .HasNoMoreProblems();
        }

        [TestMethod]
        public void No_problem_if_Remove_is_used_with_untyped_DataRow()
        {
            new UseTypedDataSetFeatures()
                .RunMethodRule(
                    () =>
                    {
                        var ds = (TestDataSet)null;
                        var row = (DataRow)null;
                        ds.TestTable.Rows.Remove(row);
                    })
                .HasNoMoreProblems();
        }

        [TestMethod]
        public void Suggest_using_RemoveXxxRow_if_DataRow_is_typed()
        {
            new UseTypedDataSetFeatures()
                .RunMethodRule(
                    () =>
                    {
                        var ds = (TestDataSet)null;
                        var row = (TestDataSet.TestTableRow)null;
                        ds.TestTable.Rows.Remove(row);
                    })
                .HasProblem(
                    100,
                    FixCategories.NonBreaking,
                    MessageLevel.Warning,
                    "Use table.RemoveTestTableRow(row) instead of table.Rows.Remove(row).")
                .HasNoMoreProblems();
        }

        [TestMethod]
        public void The_RemoveXxxRow_method_defined_in_the_typed_DataSet_is_ignored()
        {
            var removeTestTableRowMethod = typeof(TestDataSet.TestTableDataTable).GetTypeNode()
                .GetMethod(method => (method.Name.Name == "RemoveTestTableRow") && (method.Parameters.Count == 1));

            new UseTypedDataSetFeatures()
                .RunMethodRule(removeTestTableRowMethod)
                .HasNoMoreProblems();
        }
    }
}